package com.ifcar.app.util;

import java.util.ArrayList;
import java.util.List;

import android.database.DataSetObserver;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListAdapter;
import android.widget.SectionIndexer;

import com.commonsware.cwac.sacklist.SackOfViewsAdapter;

/**
* Adapter that merges multiple child adapters and views
* into a single contiguous whole.
*
* Adapters used as pieces within MergeAdapter must
* have view type IDs monotonically increasing from 0. Ideally,
* adapters also have distinct ranges for their row ids, as
* returned by getItemId().
*
*/
public class MergeAdapter extends BaseAdapter implements SectionIndexer {
private ArrayList<ListAdapter> pieces=new ArrayList<ListAdapter>();

/**
	* Stock constructor, simply chaining to the superclass.
*/
public MergeAdapter() {	
	super();
}

/**
	* Adds a new adapter to the roster of things to appear
	* in the aggregate list.
	* @param adapter Source for row views for this section
*/
public void addAdapter(ListAdapter adapter) {
	pieces.add(adapter);
	adapter.registerDataSetObserver(new CascadeDataSetObserver());
}

/**
	* Adds a new View to the roster of things to appear
	* in the aggregate list.
	* @param view Single view to add
*/
public void addView(View view) {
	addView(view, false);
}

/**
	* Adds a new View to the roster of things to appear
	* in the aggregate list.
	* @param view Single view to add
	* @param enabled false if views are disabled, true if enabled
*/
public void addView(View view, boolean enabled) {
	ArrayList<View> list=new ArrayList<View>(1);
	
	list.add(view);
	
	addViews(list, enabled);
}

/**
	* Adds a list of views to the roster of things to appear
	* in the aggregate list.
	* @param views List of views to add
*/
public void addViews(List<View> views) {
	addViews(views, false);
}

/**
	* Adds a list of views to the roster of things to appear
	* in the aggregate list.
	* @param views List of views to add
	* @param enabled false if views are disabled, true if enabled
*/
public void addViews(List<View> views, boolean enabled) {
	if (enabled) {
		addAdapter(new EnabledSackAdapter(views));
	}
	else {
		addAdapter(new SackOfViewsAdapter(views));
	}
}

/**
	* Get the data item associated with the specified
	* position in the data set.
	* @param position Position of the item whose data we want
*/
@Override
public Object getItem(int position) {
	for (ListAdapter piece : pieces) {
		int size=piece.getCount();

		if (position<size) {
			return(piece.getItem(position));
		}

		position-=size;
	}
	
	return(null);
}

/**
	* Get the adapter associated with the specified
	* position in the data set.
	* @param position Position of the item whose adapter we want
*/
public ListAdapter getAdapter(int position) {
	for (ListAdapter piece : pieces) {
		int size=piece.getCount();

		if (position<size) {
			return(piece);
		}

		position-=size;
	}
	
	return(null);
}

/**
	* How many items are in the data set represented by this
	* Adapter.
*/
@Override
public int getCount() {
	int total=0;
	
	for (ListAdapter piece : pieces) {
		total+=piece.getCount();
	}
	
	return(total);
}

/**
	* Returns the number of types of Views that will be
	* created by getView().
*/
@Override
public int getViewTypeCount() {
	int total=0;
	
	for (ListAdapter piece : pieces) {
		total+=piece.getViewTypeCount();
	}
	
	return(Math.max(total, 1));		// needed for setListAdapter() before content add'
}

/**
	* Get the type of View that will be created by getView()
	* for the specified item.
	* @param position Position of the item whose data we want
*/
@Override
public int getItemViewType(int position) {
	int typeOffset=0;
	int result=-1;
	
	for (ListAdapter piece : pieces) {
		int size=piece.getCount();

		if (position<size) {
			result=typeOffset+piece.getItemViewType(position);
			break;
		}

		position-=size;
		typeOffset+=piece.getViewTypeCount();
	}

	return(result);
}

/**
	* Are all items in this ListAdapter enabled? If yes it
	* means all items are selectable and clickable.
*/
@Override
public boolean areAllItemsEnabled() {
	return(false);
}

/**
	* Returns true if the item at the specified position is
	* not a separator.
	* @param position Position of the item whose data we want
*/
@Override
public boolean isEnabled(int position) {
	for (ListAdapter piece : pieces) {
		int size=piece.getCount();

		if (position<size) {
			return(piece.isEnabled(position));
		}

		position-=size;
	}
	
	return(false);
}

/**
	* Get a View that displays the data at the specified
	* position in the data set.
	* @param position Position of the item whose data we want
	* @param convertView View to recycle, if not null
	* @param parent ViewGroup containing the returned View
*/
@Override
public View getView(int position, View convertView,
										ViewGroup parent) {
	for (ListAdapter piece : pieces) {
		int size=piece.getCount();

		if (position<size) {
			
			return(piece.getView(position, convertView, parent));
		}

		position-=size;
	}
	
	return(null);
}

/**
	* Get the row id associated with the specified position
	* in the list.
	* @param position Position of the item whose data we want
*/
@Override
public long getItemId(int position) {
	for (ListAdapter piece : pieces) {
		int size=piece.getCount();
		
		if (position<size) {
			return(piece.getItemId(position));
		}

		position-=size;
	}
	
	return(-1);
}

@Override
public int getPositionForSection(int section) {
	int position=0;
	
	for (ListAdapter piece : pieces) {
		if (piece instanceof SectionIndexer) {
			Object[] sections=((SectionIndexer)piece).getSections();
			int numSections=0;
			
			if (sections!=null) {
				numSections=sections.length;
			}
			
			if (section<numSections) {
				return(position+((SectionIndexer)piece).getPositionForSection(section));
			}
			else if (sections!=null) {
				section-=numSections;
			}
		}
		
		position+=piece.getCount();
	}
	
	return(0);
}

@Override
public int getSectionForPosition(int position) {
	int section=0;
	
	for (ListAdapter piece : pieces) {
		int size=piece.getCount();
		
		if (position<size) {
			if (piece instanceof SectionIndexer) {
				return(section+((SectionIndexer)piece).getSectionForPosition(position));
			}
			
			return(0);
		}
		else {
			if (piece instanceof SectionIndexer) {
				Object[] sections=((SectionIndexer)piece).getSections();
				
				if (sections!=null) {
					section+=sections.length;
				}
			}
		}
		
		position-=size;
	}
	
	return(0);
}

@Override
public Object[] getSections() {
	ArrayList<Object> sections=new ArrayList<Object>();
	
	for (ListAdapter piece : pieces) {
		if (piece instanceof SectionIndexer) {
			Object[] curSections=((SectionIndexer)piece).getSections();
			
			if (curSections!=null) {
				for (Object section : curSections) {
					sections.add(section);
				}
			}
		}
	}
	
	if (sections.size()==0) {
		return(null);
	}

	return(sections.toArray(new Object[0]));
}

private static class EnabledSackAdapter extends SackOfViewsAdapter {
	public EnabledSackAdapter(List<View> views) {
		super(views);
	}

	@Override
	public boolean areAllItemsEnabled() {
		return(true);
	}
	
	@Override
	public boolean isEnabled(int position) {
		return(true);
	}
}

private class CascadeDataSetObserver extends DataSetObserver {
	@Override
	public void onChanged() {
		notifyDataSetChanged();
	}
	
	@Override
	public void onInvalidated() {
		notifyDataSetInvalidated();
	}
}
}

